package com.istock.union.user.service.impl;

import java.text.ParseException;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.istock.base.common.api.model.ApiBaseResponse;
import com.istock.base.common.api.model.PageInfo;
import com.istock.base.common.api.model.RetStatusEnum;
import com.istock.base.enumration.Enums;
import com.istock.base.mybatis.utils.MybatisFieldConvertUtils;
import com.istock.base.spring.dynamicLoad.PropertyStaticLoader;
import com.istock.union.user.client.SSOClientUtils;
import com.istock.union.user.dao.CredentialRoleInfoMapper;
import com.istock.union.user.dao.UserCredentialInfoMapper;
import com.istock.union.user.dao.UserInfoMapper;
import com.istock.union.user.dao.ext.ExtUserInfoMapper;
import com.istock.union.user.model.Constants;
import com.istock.union.user.model.CredentialRoleInfo;
import com.istock.union.user.model.CredentialRoleInfoExample;
import com.istock.union.user.model.DeptInfo;
import com.istock.union.user.model.RoleInfo;
import com.istock.union.user.model.SSOUser;
import com.istock.union.user.model.UserCredentialInfo;
import com.istock.union.user.model.UserCredentialInfoExample;
import com.istock.union.user.model.UserDept;
import com.istock.union.user.model.UserInfo;
import com.istock.union.user.model.UserInfoExample;
import com.istock.union.user.model.UserInfoQueryModel;
import com.istock.union.user.model.UserRole;
import com.istock.union.user.model.ext.UserInfoVO;
import com.istock.union.user.service.DeptInfoService;
import com.istock.union.user.service.RoleInfoService;
import com.istock.union.user.service.UserCredentialInfoService;
import com.istock.union.user.service.UserInfoService;
import com.istock.union.user.util.MD5Utils;

@Repository
public class UserInfoServiceImpl implements UserInfoService{

	@Autowired
	private UserInfoMapper mapper;
	@Autowired
	private ExtUserInfoMapper extUserInfoMapper;
	@Autowired
	private RoleInfoService roleInfoService;
	@Autowired
	private SqlSessionFactoryBean sessionFactory;
	@Autowired
	private DeptInfoService deptInfoService;
	@Autowired
	private UserCredentialInfoMapper userCredentialMapper;
	@Autowired
	private UserCredentialInfoService userCredentialService;
	@Autowired
	private CredentialRoleInfoMapper credentialRoleMapper;
	
	private Logger logger = LoggerFactory.getLogger(getClass());
	
	public boolean isAdmin(SSOUser ssoUser){
		return "admin".equalsIgnoreCase(ssoUser.getLoginName());
	}
	
	public List<UserInfoVO> selectUserVOListByPage(UserInfoQueryModel user, PageInfo<UserInfoVO> page){
		Map<String , Object> paramMap = new HashMap<String , Object>();
		if(user != null) {
			if(StringUtils.isNoneBlank(user.getBeginTime())) {
				try {
					paramMap.put("beginTime", DateUtils.parseDate(user.getBeginTime()));
				} catch (ParseException e) {
					logger.error("beginTime parse exception", e);
				}
			}
			
			if(StringUtils.isNotBlank(user.getEndTime())) {
				try {
					paramMap.put("endTime", DateUtils.parseDate(user.getEndTime()));
				} catch (ParseException e) {
					logger.error("endTime parse exception", e);
				}
			}
			
			if(StringUtils.isNotBlank(user.getLoginName())) {
				paramMap.put("loginName", "%"+user.getLoginName()+"%");
			}
			if(user.getDeptCode() != null) {
				paramMap.put("deptCode", Arrays.asList(user.getDeptCode()));
			}
			
			if(StringUtils.isNotBlank(user.getOrderByColumn())) {
//				paramMap.put("orderByClause", "U."+NamedConverter.HumpToUnderline(user.getOrderByColumn())+" "+user.getIsAsc());
				paramMap.put("orderByClause", "U."+MybatisFieldConvertUtils.getInstance().unmarshal("com.istock.union.user.dao.UserInfoMapper", "BaseResultMap", user.getOrderByColumn())+" "+user.getIsAsc());
			}
			
		}
		return extUserInfoMapper.selectUserListByPage(paramMap, page);
	}
	
	public List<UserInfo> selectUserListByPage(UserInfoQueryModel user, PageInfo<UserInfo> page) {
		UserInfoExample example = new UserInfoExample();
		UserInfoExample.Criteria criteria = example.createCriteria();
		if(user != null) {
			
			
			if (StringUtils.isNotBlank(user.getBeginTime())) {
				try {
					criteria.andCreateTimeGreaterThanOrEqualTo(DateUtils.parseDate(user.getBeginTime()));
				} catch (ParseException e) {
					logger.error("beginTime parse exception", e);
				}
			}
			
			if (StringUtils.isNotBlank(user.getBeginTime())) {
				try {
					criteria.andCreateTimeLessThanOrEqualTo(DateUtils.parseDate(user.getBeginTime()));
				} catch (ParseException e) {
					logger.error("endTime parse exception", e);
				}
			}
			
			if(StringUtils.isNotBlank(user.getLoginName())) {
				criteria.andLoginNameLike("%"+user.getLoginName()+"%");
			}
			if(user.getDeptCode() != null) {
				//criteria.andDeptCodeEqualTo(user.getDeptCode());
				criteria.andDeptCodeIn(Arrays.asList(user.getDeptCode()));
			}
			
			if(StringUtils.isNotBlank(user.getOrderByColumn())) {
//				example.setOrderByClause(NamedConverter.HumpToUnderline(user.getOrderByColumn())+" "+user.getIsAsc());
				example.setOrderByClause(MybatisFieldConvertUtils.getInstance().unmarshal("com.istock.union.user.dao.UserInfoMapper", "BaseResultMap", user.getOrderByColumn())+" "+user.getIsAsc());
			}
			
		}
		return mapper.selectByExample(example, page);
	}
	
	@Transactional
	public void insertUser(UserInfo user , List<String> roleIdList) {
		// 新增用户信息
		// 没有值的时候设置默认值
		user.setCreateTime(new Date());
		user.setStatus(Constants.COMMON_VALID);
		user.setSalt(MD5Utils.genSalt());
		user.setPassword(MD5Utils.genSaltMD5(user.getPassword() , user.getSalt()));
		user.setCreateBy(SSOClientUtils.getInstance().findCurrentUser().getUserName());
		user.setPasswdExpire(DateUtils.addDays(new Date(), Integer.parseInt(PropertyStaticLoader.getInstance().findProperty("system.passwd.expire", "90"))));
		mapper.insertSelective(user);
		// 新增用户岗位关联
//		insertUserPosts(user.getId(), Arrays.asList(user.getPostIds()));
		
		// 新增用户与身份的管理
		//新增用户,在用户身份表中创建本职身份关联
		UserCredentialInfo userCredentialInfo = new UserCredentialInfo();
		userCredentialInfo.setDeptCode(user.getDeptCode());
		userCredentialInfo.setType(Enums.getInstance().getEnumsValueByCode("CREDENTIAL_TYPE", "CREDENTIAL_TYPE_OWNER"));
		userCredentialInfo.setUserId(user.getId());
		userCredentialMapper.insertSelective(userCredentialInfo);
		
		insertUserRoles(userCredentialInfo.getId(), roleIdList);
	}
	
	private void insertUserRoles(String credentialId, List<String> roleIds) {
		try {
			if (!CollectionUtils.isEmpty(roleIds)) {
				SqlSession session = sessionFactory.getObject().openSession(ExecutorType.BATCH);
				CredentialRoleInfoMapper credentialMapper = session.getMapper(CredentialRoleInfoMapper.class);
				for (String roleId : roleIds) {
					CredentialRoleInfo up = new CredentialRoleInfo();
					up.setCredentialId(credentialId);
					up.setRoleId(roleId);
					credentialMapper.insertSelective(up);
				}
				session.flushStatements();
			}
			
		} catch (Exception e) {
			logger.error("Data user role insert exception ", e);
		}
	}
	
	@Transactional
	public void updateUser(UserInfo user , List<String> roleList) {
		String userId = user.getId();
		// 删除用户与身份关联
		UserCredentialInfoExample userCredentialExample = new UserCredentialInfoExample();
		userCredentialExample.createCriteria().andUserIdEqualTo(userId).andTypeEqualTo(Enums.getInstance().getEnumsValueByCode("CREDENTIAL_TYPE", "CREDENTIAL_TYPE_OWNER"));
		List<UserCredentialInfo> userCredentialInfoList = userCredentialMapper.selectByExample(userCredentialExample);
		
		//删除身份和角色的关联
		CredentialRoleInfoExample credentialRoleExample = new CredentialRoleInfoExample();
		credentialRoleExample.createCriteria().andCredentialIdEqualTo(userCredentialInfoList.get(0).getId());
		credentialRoleMapper.deleteByExample(credentialRoleExample);
		
		// 新增身份与角色管理
		insertUserRoles(userCredentialInfoList.get(0).getId(), roleList);
		// 删除用户与岗位关联
		/*UserPostInfoExample upExample = new UserPostInfoExample();
		upExample.createCriteria().andUserIdEqualTo(userId);
		userPostInfoMapper.deleteByExample(upExample);*/
		// 新增用户与岗位管理
//		insertUserPosts(user.getId(), Arrays.asList(user.getPostIds()));
//		UserInfo record = BeanUtils.propertiesCopy(user, new UserInfo());
		
		mapper.updateByPrimaryKeySelective(user);
		/*if (num != 1) {
			logger.error("Data user update failed, expect 1, but {}, id {}", num, record.getId());
			throw new DMLExecuteException(ExceptionConstants.DATA_INSERT_EXCEPTION_MESSAGE);
		}*/
	}
	
	/**
	 * 校验密码，已知用户ID，方便内部使用，通过之后返回用户信息
	 * 
	 * @param userId
	 * @param password
	 * @return
	 */
	public ApiBaseResponse<SSOUser> checkPasswd(String userName, String passwd, String tenantCode) {
		UserInfoExample example = new UserInfoExample();
		UserInfoExample.Criteria criteria = example.createCriteria();
		criteria.andLoginNameEqualTo(userName);
		if(StringUtils.isNotBlank(tenantCode)) {
			criteria.andTenantCodeEqualTo(tenantCode);
		}
		List<UserInfo> userList = mapper.selectByExample(example);
		if(userList != null && userList.size()>0){
			UserInfo userInfo = userList.get(0);
			boolean result = MD5Utils.verifySaltMD5(passwd,userInfo.getSalt(),userInfo.getPassword());
			SSOUser ssoUser = new SSOUser();
			ssoUser.setTenantNo(userInfo.getTenantCode());
			ssoUser.setUserId(userInfo.getId());
			ssoUser.setUserName(userInfo.getUserName());
			ssoUser.setLoginName(userInfo.getLoginName());
			
			//在没有委任之前,一个用户的登录,只能登陆一个机构
			if(StringUtils.isNotBlank(userInfo.getDeptCode())) {
				DeptInfo deptInfo = deptInfoService.selectDeptByCode(userInfo.getDeptCode());
				UserDept userDept = new UserDept();
				userDept.setDeptCode(deptInfo.getDeptCode());
				userDept.setDeptName(deptInfo.getDeptName());
				userDept.setTenantCode(deptInfo.getTenantCode());
				userDept.setAncestor(deptInfo.getAncestors());
				ssoUser.setOwnDept(userDept);
			}
			
			if(!isAdmin(ssoUser)) {
//				List<UserRoleDeptInfo> roleDeptList = userRoleDeptInfoService.findUserRoleDeptList(ssoUser.getUserId());
				List<UserCredentialInfo> userCredentialList = userCredentialService.findUserCredentialList(ssoUser.getUserId());
				ssoUser.setJobCount(userCredentialList.size());
				if(userCredentialList != null && userCredentialList.size() == 1) {
					//没有委任的用户,设置当前登录机构为用户的所属机构
					UserDept copyDept = new UserDept();
					BeanUtils.copyProperties(ssoUser.getOwnDept(), copyDept);
					ssoUser.setCurrentDept(copyDept);
					
					//设置当前的身份ID
					ssoUser.setCredentialId(userCredentialList.get(0).getId());
					
					List<RoleInfo> roleList = roleInfoService.selectUserRolesByUserId(userInfo.getId());
					if(roleList != null) {
						for(RoleInfo roleInfo : roleList) {
							UserRole userRole = new UserRole();
							userRole.setId(roleInfo.getId());
							userRole.setRoleKey(roleInfo.getRoleKey());
							userRole.setRoleName(roleInfo.getRoleName());
							ssoUser.getRoleInfoSet().add(userRole);
						}
					}
				}
			}
			
			if(result) {
				return new ApiBaseResponse<SSOUser>(RetStatusEnum.SUCCESS , "T000" , "密码校验成功" , ssoUser);
			}else {
				return new ApiBaseResponse<SSOUser>(RetStatusEnum.FAIL , "T002" , "密码不匹配" , null);
			}
		}else{
			return new ApiBaseResponse<SSOUser>(RetStatusEnum.FAIL , "T001" , "用户名找不到" , null);
		}
	}
	
	public ApiBaseResponse<UserInfo> checkUserPasswd(String userId, String passwd) {
		UserInfoExample example = new UserInfoExample();
		UserInfoExample.Criteria criteria = example.createCriteria();
		criteria.andIdEqualTo(userId);
		List<UserInfo> userList = mapper.selectByExample(example);
		if(userList != null && userList.size()>0){
			UserInfo userInfo = userList.get(0);
			boolean result = MD5Utils.verifySaltMD5(passwd, userInfo.getSalt(),userInfo.getPassword());
			if(result) {
				return new ApiBaseResponse<UserInfo>(RetStatusEnum.SUCCESS , "T000" , "密码校验成功" , userInfo);
			}else {
				return new ApiBaseResponse<UserInfo>(RetStatusEnum.FAIL , "T002" , "密码不匹配" , null);
			}
		}else{
			return new ApiBaseResponse<UserInfo>(RetStatusEnum.FAIL , "T001" , "用户名找不到" , null);
		}
	}
	
	/**
	 * 修改密码，修改密码并且添加密码记录
	 * 
	 * @param user
	 * @param confirmNewPassword
	 */
	@Transactional
	public void changePassword(String userId, String confirmNewPassword) {
		
		UserInfo userInfo = mapper.selectByPrimaryKey(userId);
		
		UserInfo record = new UserInfo();
		record.setId(userId);
		//不用每次都更新盐
//		record.setSalt(MD5Utils.genSalt());
		record.setPassword(MD5Utils.genSaltMD5(confirmNewPassword , userInfo.getSalt()));
		record.setUpdateTime(new Date());
		record.setPasswdExpire(DateUtils.addDays(new Date(), Integer.parseInt(PropertyStaticLoader.getInstance().findProperty("system.passwd.expire", "90"))));
		mapper.updateByPrimaryKeySelective(record);
	}
	
	@Transactional
	public void deleteUserByIds(List<String> ids) {
		if (CollectionUtils.isEmpty(ids)) {
			return;
		}
		UserInfoExample example = new UserInfoExample();
		example.createCriteria().andIdIn(ids);
		mapper.deleteByExample(example);
		// 逻辑密码记录
		/*PasswordRecordExample prExample = new PasswordRecordExample();
		prExample.createCriteria().andUserIdIn(ids);
		passwordRecordMapper.deleteByExample(prExample);*/
		// 删除用户与身份关联
		UserCredentialInfoExample userCredentialInfoExample = new UserCredentialInfoExample();
		userCredentialInfoExample.createCriteria().andUserIdIn(ids);
		userCredentialMapper.deleteByExample(userCredentialInfoExample);
	}
	
	/**
	 * 修改用户信息
	 * 
	 * @param user
	 */
	public int updateUserStatus(String userId,Integer status , String opName) {
		UserInfo userInfo = new UserInfo();
		userInfo.setId(userId);
		userInfo.setStatus(status);
		userInfo.setUpdateTime(new Date());
		userInfo.setUpdateBy(opName);
		return mapper.updateByPrimaryKeySelective(userInfo);
	}
	
	/**
	 * 根据ID查询用户详细信息
	 * 
	 * @param id
	 * @return
	 */
	public UserInfo selectUserDetailsById(String id) {
		return mapper.selectByPrimaryKey(id);
	}
	
	/**
	 * 检查登录用户名是否唯一
	 * 
	 * @param user
	 * @return
	 */
	public Boolean checkLoginNameUnique(UserInfo user) {
		UserInfoExample example = new UserInfoExample();
		UserInfoExample.Criteria criteria = example.createCriteria();
		criteria.andLoginNameEqualTo(user.getLoginName());
		criteria.andTenantCodeEqualTo(user.getTenantCode());
		if (StringUtils.isNotBlank(user.getId())) {
			criteria.andIdNotEqualTo(user.getId());
		}
		return mapper.countByExample(example) == 0;
	}

	/**
	 * 检查电话号是否唯一
	 * 
	 * @param user
	 * @return
	 */
	public Boolean checkPhoneUnique(UserInfo user) {
		UserInfoExample example = new UserInfoExample();
		UserInfoExample.Criteria criteria = example.createCriteria();
		criteria.andPhoneNumberEqualTo(user.getPhoneNumber());
		if (StringUtils.isNotBlank(user.getId())) {
			criteria.andIdNotEqualTo(user.getId());
		}
		return mapper.countByExample(example) == 0;
	}
	
	/**
	 * 检查邮箱是否唯一
	 * 
	 * @param user
	 * @return
	 */
	public Boolean checkEmailUnique(UserInfo user) {
		UserInfoExample example = new UserInfoExample();
		UserInfoExample.Criteria criteria = example.createCriteria();
		criteria.andEmailEqualTo(user.getEmail());
		if (StringUtils.isNotBlank(user.getId())) {
			criteria.andIdNotEqualTo(user.getId());
		}
		return mapper.countByExample(example) == 0;
	}
}
